<script setup lang="ts">
import { reactive, ref } from 'vue';
import 'dayjs/locale/zh-cn' // 日期和时间本地化
import { type FormInstance, type FormRules } from 'element-plus';

/** 表单字段接口 */
interface RuleForm {
    name: string,
    age: number,
    address: string,
    createTime: Date
}

/** 表单实例引用 */
const ruleFormRef = ref<FormInstance>()
/** 表单字段初始化 */
const ruleForm = reactive<RuleForm>({
    name: '',
    age: 0,
    address: '',
    createTime: new Date()
})

const ageRemoteLoading = ref(false);
/** 自定义校验规则 - 验证年龄 */
const checkAge = (rule: any, value: any, callback: any) => {
    if (!value) {
        return callback(new Error('请填写年龄'))
    }

    ageRemoteLoading.value = true;
    // 延时校验。模拟远程校验功能
    setTimeout(() => {
        ageRemoteLoading.value = false;

        if (!Number.isInteger(value)) {
            callback(new Error('请填写有效的年龄'))
        } else {
            if (value < 18) {
                callback(new Error('年龄不能小于 18'))
            } else {
                callback();
            }
        }
    }, 1000)
}

/** 表单验证规则 */
const rules = reactive<FormRules<RuleForm>>({
    name: [
        { required: true, message: '请填写姓名', trigger: 'blur' },
        { min: 2, max: 4, message: '名字长度只能在 2 到 4 个文字', trigger: 'blur' }
    ],
    age: [
        { validator: checkAge, trigger: 'blur' }
    ],
    address: [
        { required: true, message: '请填写地址', trigger: 'blur' }
    ]
})

/** 提交表单 */
const submitForm = async (formEl: FormInstance | undefined) => {
    if (!formEl) { return; }
    await formEl.validate((valid, fields) => {
        if (valid) {
            console.log('提交', ruleForm);
        } else {
            console.error('提交出现异常', fields);
        }
    })
}

/** 重置表单 */
const resetForm = (formEl: FormInstance | undefined) => {
    if (!formEl) { return; }
    formEl.resetFields();
}

const visible = ref(false);
const editId = ref(0);
const openDialog = (id: number) => {
    visible.value = true;
    editId.value = id;

    // 模拟通过接口获取数据
    setTimeout(() => {
        ruleForm.name = 'Tom';
        ruleForm.age = 18;
        ruleForm.address = '厦门';
        ruleForm.createTime = new Date();
    }, 1500);
}

// 对外暴露方法
defineExpose({
    openDialog
})

</script>

<template>
    <el-dialog v-model="visible" @close="resetForm(ruleFormRef); visible = false" width="400" draggable
        :close-on-press-escape="false" :close-on-click-modal="false"
        header-class="custom-dialog-header" footer-class="custom-dialog-footer">
        <template #header>
            编辑： {{ editId }}
        </template>

        <el-scrollbar height="300px">
            <el-form ref="ruleFormRef" :model="ruleForm" :rules="rules">
                <el-form-item label="姓名" prop="name" label-width="50px">
                    <el-input v-model="ruleForm.name" autocomplete="off" style="width: 120px;" />
                </el-form-item>
                <el-form-item label="年龄" prop="age" label-width="50px">
                    <el-input v-model.number="ruleForm.age" autocomplete="off" style="width: 60px;">
                        <template #suffix>
                            <el-icon v-show="ageRemoteLoading">
                                <Loading />
                            </el-icon>
                        </template>
                    </el-input>
                </el-form-item>
                <el-form-item label="地址" prop="address" label-width="50px">
                    <el-input v-model="ruleForm.address" autocomplete="off" style="width: 200px;" />
                </el-form-item>
                <el-form-item label="日期" prop="createTime" label-width="50px">
                    <el-date-picker v-model="ruleForm.createTime" type="date" placeholder="请选择日期" />
                </el-form-item>
            </el-form>
        </el-scrollbar>

        <template #footer>
            <div class="dialog-footer">
                <el-button @click="resetForm(ruleFormRef); visible = false">取消</el-button>
                <el-button type="primary" @click="submitForm(ruleFormRef)">保存</el-button>
            </div>
        </template>

    </el-dialog>
</template>

<style lang="scss" scoped>
</style>